/*
 * VertexBuffer.h
 *
 *  Created on: 2011/06/22
 *      Author: naoki
 */

#ifndef INCLUDED_NTENGINE_GRAPHICS_VERTEXBUFFER_H
#define INCLUDED_NTENGINE_GRAPHICS_VERTEXBUFFER_H

#include "NTEngine/Graphics/Vertex.h"

namespace NTEngine {
namespace Xml {
class ConstElement;
} // namespace Xml
namespace Math {
class Matrix3x4;
} // namespace Math

namespace Graphics {

/**
 * @brief 頂点バッファ
 */
class VertexBuffer {
public:
	/**
	 * @brief フォーマット
	 */
	enum Format {
		FORMAT_VERTEX, /// 汎用頂点
		FORMAT_BLENDINGVERTEX, /// 頂点ブレンド
	};

	/**
	 * @brief メモリの管理方法
	 */
	enum Managed {
		MANAGED_STATIC, /// 静的管理。GPU側に配置する[Write Only]
		MANAGED_DYNAMIC, /// 動的管理。CPU側に配置する[Read/Write]
	};

	/**
	 * @brief XMLエレメントから生成します。
	 */
	static VertexBuffer create( Xml::ConstElement );

	/**
	 * @brief 指定の頂点数だけ確保して生成します。
	 */
	static VertexBuffer create( int vertexNumber, Format fmt = FORMAT_VERTEX, Managed mng = MANAGED_STATIC );

	/**
	 * @brief グラフィックスメモリ書き込み用のバッファを確保します
	 * この機能により取得したバッファはunlockによって適切に処理してください
	 *
	 * @param T** 次の型Vertex
	 */
	template< class T >
	void lock( T** );

	/**
	 * @brief グラフィックスメモリに書き込み、書き込み用のバッファを破棄します
	 * lockで取得したバッファを指定してください。
	 *
	 * @param T** lockで取得したバッファ
	 */
	template< class T >
	void unlock( T** );

	/**
	 * @brief 名前を取得します。
	 */
	const char* name() const;

	/**
	 * @brief 頂点数を取得します。
	 */
	int vertexNumber() const;

	/**
	 * @brief フォーマットを取得します
	 */
	Format format() const;

	Managed managed() const;

	void updateSkin( const Matrix3x4* matrixPallete, int matrixNumber );

	// 非公開
	VertexBuffer();
	~VertexBuffer();
	VertexBuffer( const VertexBuffer& );
	void release();
	VertexBuffer& operator=( const VertexBuffer& );
	bool operator==( const VertexBuffer& ) const;
	bool operator!=( const VertexBuffer& ) const;
	int referenceCount() const;
	operator void*() const;
	class Impl;
	VertexBuffer( const Impl* );
private:
	friend class Manager;
	Impl* mImpl;
};

// ここで許可した型のみVertexBufferのlock,unlockが可能
#define ALLOW_LOCK_UNLOCK_TYPE( vertex_type ) \
template<> void VertexBuffer::lock( vertex_type** );\
template<> void VertexBuffer::unlock( vertex_type** );

ALLOW_LOCK_UNLOCK_TYPE( Vertex )
ALLOW_LOCK_UNLOCK_TYPE( BlendingVertex )
#undef ALLOW_LOCK_UNLOCK_TYPE

} // namespace Graphics
} // namespace NTEngine

#endif // INCLUDED_NTENGINE_GRAPHICS_VERTEXBUFFER_H
